<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  
  <title>stream | 个人博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="buffer 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980&#x2F;&#x2F; buffer 代表的就是缓存区域的内容，早期js没有读取文件的能力 （前端多">
<meta property="og:type" content="article">
<meta property="og:title" content="stream">
<meta property="og:url" content="https://gitee.com/wieldy/bailment-blog/2022/03/29/stream/index.html">
<meta property="og:site_name" content="个人博客">
<meta property="og:description" content="buffer 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980&#x2F;&#x2F; buffer 代表的就是缓存区域的内容，早期js没有读取文件的能力 （前端多">
<meta property="og:locale" content="en_US">
<meta property="article:published_time" content="2022-03-29T14:12:00.000Z">
<meta property="article:modified_time" content="2023-04-23T12:11:43.652Z">
<meta property="article:author" content="John Doe">
<meta name="twitter:card" content="summary">
  
    <link rel="alternate" href="/bailment-blog/atom.xml" title="个人博客" type="application/atom+xml">
  
  
    <link rel="shortcut icon" href="/bailment-blog/favicon.png">
  
  
    
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-source-code-pro@0.0.71/index.min.css">

  
  
<link rel="stylesheet" href="/bailment-blog/css/style.css">

  
    
<link rel="stylesheet" href="/bailment-blog/fancybox/jquery.fancybox.min.css">

  
<meta name="generator" content="Hexo 6.3.0"></head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/bailment-blog/" id="logo">个人博客</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/bailment-blog/">Home</a>
        
          <a class="main-nav-link" href="/bailment-blog/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/bailment-blog/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="https://gitee.com/wieldy/bailment-blog"></form>
      </div>
    </div>
  </div>
</header>

      <div class="outer">
        <section id="main"><article id="post-stream" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/bailment-blog/2022/03/29/stream/" class="article-date">
  <time class="dt-published" datetime="2022-03-29T14:12:00.000Z" itemprop="datePublished">2022-03-29</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="p-name article-title" itemprop="headline name">
      stream
    </h1>
  

      </header>
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        <ul>
<li><p>buffer</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// buffer 代表的就是缓存区域的内容，早期js没有读取文件的能力 （前端多数都是字符串）。 在node中读取出的内容都是二进制格式</span></span><br><span class="line"><span class="comment">// buffer优点可以将二进制和我们的字符串相互转化  buffer代表的是内存 （内存地址 引用类型） buffer默认声明的时候都是固定大小的</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 声明buffer的三种方式</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> b1 = <span class="title class_">Buffer</span>.<span class="title function_">from</span>(<span class="string">&#x27;珠峰&#x27;</span>); <span class="comment">// node中默认不支持gbk编码 (在utf8中一个汉字是三个字节)</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(b1.<span class="title function_">toString</span>(<span class="string">&#x27;base64&#x27;</span>)); <span class="comment">// 可以将buffer转成对应的编码 utf8/base64</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> b2 = <span class="title class_">Buffer</span>.<span class="title function_">alloc</span>(<span class="number">6</span>); <span class="comment">// buffer中的单位都是字节（最小单位了）</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(b2);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> b3 = <span class="title class_">Buffer</span>.<span class="title function_">from</span>([<span class="number">0x64</span>, <span class="number">100</span>, <span class="string">&#x27;abc&#x27;</span>, <span class="number">257</span>]); <span class="comment">// 这种方式基本用不到</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(b3)</span><br><span class="line"></span><br><span class="line"><span class="comment">// ascii  -&gt;  gb18030  -&gt; gbk -&gt; unicode  -&gt; utf8</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Buffer</span>.<span class="title function_">from</span>(<span class="string">&#x27;abc&#x27;</span>)); <span class="comment">// 字符串是1个字符1个字节 应用的是ASCII</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 我们要掌握buffer的常用方法和基本的api</span></span><br><span class="line"><span class="comment">// 将多个buffer拼接在一起</span></span><br><span class="line"><span class="keyword">const</span> b4 = <span class="title class_">Buffer</span>.<span class="title function_">from</span>(<span class="string">&#x27;珠峰&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> b5 = <span class="title class_">Buffer</span>.<span class="title function_">from</span>(<span class="string">&#x27;架构&#x27;</span>);  <span class="comment">// 扩容处理 （就是声明一个更大的将以前的放进去） copy</span></span><br><span class="line"><span class="title class_">Buffer</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">copy</span> = <span class="keyword">function</span> (<span class="params">target, targetStart, sourceStart = <span class="number">0</span>, sourceEnd = <span class="variable language_">this</span>.length</span>) &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; sourceEnd - sourceStart; i++) &#123;</span><br><span class="line">        target[targetStart + i] = <span class="variable language_">this</span>[sourceStart + i]; <span class="comment">// buffer中存放的都是引用类型</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/* const bigBuffer = Buffer.alloc(b4.length + b5.length); // 取的是字节长度</span></span><br><span class="line"><span class="comment">b4.copy(bigBuffer, 0) // npm install @types/node (node中的ts的声明文件)</span></span><br><span class="line"><span class="comment">b5.copy(bigBuffer, b4.length);</span></span><br><span class="line"><span class="comment">b6.copy(bigBuffer, b4.length + b5.length);</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="title class_">Buffer</span>.<span class="property">concat</span> = <span class="keyword">function</span> (<span class="params">list, totalLength = list.reduce((memo, current) =&gt; memo += current.length, <span class="number">0</span>)</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> bigBuffer = <span class="title class_">Buffer</span>.<span class="title function_">alloc</span>(totalLength);</span><br><span class="line">    <span class="keyword">let</span> pos = <span class="number">0</span>;</span><br><span class="line">    list.<span class="title function_">forEach</span>(<span class="function"><span class="params">buf</span> =&gt;</span> &#123;</span><br><span class="line">        buf.<span class="title function_">copy</span>(bigBuffer, pos);</span><br><span class="line">        pos += buf.<span class="property">length</span></span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">return</span> bigBuffer</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> bigBuffer = <span class="title class_">Buffer</span>.<span class="title function_">concat</span>([b4, b5]); <span class="comment">// 这个方法经常用到</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果自己分析数据 行读取器 每读取一行就打印一下，  遇到关键字就做处理</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> buf = <span class="title class_">Buffer</span>.<span class="title function_">from</span>(<span class="string">&#x27;1---哈哈---name=zf---age=13&#x27;</span>);</span><br><span class="line"><span class="title class_">Buffer</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">split</span> = <span class="keyword">function</span> (<span class="params">sep</span>) &#123;</span><br><span class="line">    sep = <span class="title class_">Buffer</span>.<span class="title function_">isBuffer</span>(sep) ? sep : <span class="title class_">Buffer</span>.<span class="title function_">from</span>(sep);</span><br><span class="line">    <span class="keyword">let</span> len = sep.<span class="property">length</span>; <span class="comment">// 是对应分割符的长度 是以字节为单位的</span></span><br><span class="line">    <span class="keyword">let</span> arr = [];</span><br><span class="line">    <span class="keyword">let</span> offset = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">let</span> idx = <span class="number">0</span>;</span><br><span class="line">    <span class="comment">// this的indexOf （buffer）</span></span><br><span class="line">    <span class="keyword">while</span> (-<span class="number">1</span> !== (idx = <span class="variable language_">this</span>.<span class="title function_">indexOf</span>(sep, offset))) &#123;</span><br><span class="line">        arr.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="title function_">slice</span>(offset, idx));</span><br><span class="line">        offset = idx + len</span><br><span class="line">    &#125;</span><br><span class="line">    arr.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="title function_">slice</span>(offset))</span><br><span class="line">    <span class="keyword">return</span> arr;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> arr = buf.<span class="title function_">split</span>(<span class="string">&#x27;---&#x27;</span>); <span class="comment">// 字符串的indexof</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(arr)</span><br><span class="line"></span><br><span class="line"><span class="comment">// Buffer.concat()  buffer.slice() 我们事先声明了一个100字节的buffer，但是最终只有10个有效，我们可以截取出来</span></span><br><span class="line"><span class="comment">// Buffer.isBuffer() 可以判断是不是buffer类型  我们可以统一将数据全部处理成buffer来进行操作</span></span><br><span class="line"><span class="comment">// buffer.indexOf() 可以基于封装split方法</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 和数组来类比buffer    slice()截取</span></span><br><span class="line"><span class="comment">// let arr = [[0], 1, 2, 3];</span></span><br><span class="line"><span class="comment">// const newArray = arr.slice(0, 1); // 截取的是内存空间</span></span><br><span class="line"><span class="comment">// newArray[0][0] = 100;</span></span><br><span class="line"><span class="comment">// console.log(arr)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// // ------------------------</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// let b7 = Buffer.from([1, 2, 3, 4, 5, 6]);</span></span><br><span class="line"><span class="comment">// let b8 = b7.slice(0, 1);</span></span><br><span class="line"><span class="comment">// b8[0] = 100;</span></span><br><span class="line"><span class="comment">// console.log(b7)</span></span><br></pre></td></tr></table></figure></li>
<li><p>fs</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 文件读取等操作 都是操作的都是二进制数据  fs filesystem</span></span><br><span class="line"><span class="comment">// fs.readFileSync() 同步性能 （缺陷是阻塞主线程）  fs.readFile()  （异步的非阻塞）</span></span><br><span class="line"><span class="comment">// fs.writeFileSync()                            fs.writeFile()</span></span><br><span class="line"><span class="comment">// 默认我们在做一些前置工作的时候 （前置工作采用同步的）  在程序运行的过程中防止阻塞主线程（需要采用异步）</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 拷贝一个文件</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 写入的特点是： 如果文件不存在会创建这个文件，如果文件存在，默认会清空文件 （最后写入）</span></span><br><span class="line"><span class="comment">// 读取的特点是： 如果文件不存在会报错</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 简单的文件读取是ok的~ 但是如果文件大的话不能采用这种方式。  流 （采用边读边写入的方式，暂停，控制速率的功能）</span></span><br><span class="line"><span class="comment">// fs.readFile(path.join(__dirname, &#x27;package.json&#x27;), function (err, data) &#123; // error -first模式第一个参数是错误</span></span><br><span class="line"><span class="comment">//     if (err) return err;</span></span><br><span class="line"><span class="comment">//     fs.writeFile(path.join(__dirname, &#x27;package1.json&#x27;), data, function (err) &#123;</span></span><br><span class="line"><span class="comment">//         console.log(err, &#x27;写入的err&#x27;)</span></span><br><span class="line"><span class="comment">//     &#125;)</span></span><br><span class="line"><span class="comment">// &#125;);</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// fs.open()  fs.read()  fs.write()  fs.close()  也有同步的但是主要应用还是异步api</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 64k以下的可以采用这种方式</span></span><br><span class="line"><span class="comment">// r读取  w写入  a追加</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 所谓的读取 都是写入 （是把文件中的内容，写入到内存中）</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">const BUFFER_SIZE = 3;</span></span><br><span class="line"><span class="comment">const buffer = Buffer.alloc(BUFFER_SIZE);</span></span><br><span class="line"><span class="comment">fs.open(path.resolve(__dirname, &#x27;test&#x27;), &#x27;r&#x27;, function (err, fd) &#123; // file descriptor 文件描述符（描述如何操作这个文件）</span></span><br><span class="line"><span class="comment">    // 将数据写入到buffer中 从第0个索引开始写入，写入3个. 从哪个位置开始读取</span></span><br><span class="line"><span class="comment">    fs.read(fd, buffer, 0, BUFFER_SIZE, 0, function (err, bytesRead) &#123; // bytesRead 真实读取到的个数</span></span><br><span class="line"><span class="comment">        fs.open(path.resolve(__dirname, &#x27;test1&#x27;), &#x27;w&#x27;, function (err, wfd) &#123;</span></span><br><span class="line"><span class="comment">            fs.write(wfd, buffer, 0, bytesRead, 0, function (err, written) &#123; //  written 真正写入的个数</span></span><br><span class="line"><span class="comment">                console.log(written)</span></span><br><span class="line"><span class="comment">            &#125;)</span></span><br><span class="line"><span class="comment">        &#125;)</span></span><br><span class="line"><span class="comment">    &#125;)</span></span><br><span class="line"><span class="comment">&#125;) */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">copy</span>(<span class="params">source, target, cb</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> <span class="variable constant_">BUFFER_SIZE</span> = <span class="number">3</span>;</span><br><span class="line">    <span class="keyword">const</span> buffer = <span class="title class_">Buffer</span>.<span class="title function_">alloc</span>(<span class="variable constant_">BUFFER_SIZE</span>);</span><br><span class="line">    fs.<span class="title function_">open</span>(source, <span class="string">&#x27;r&#x27;</span>, <span class="keyword">function</span> (<span class="params">err, fd</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (err) <span class="keyword">return</span> <span class="title function_">cb</span>(err)</span><br><span class="line">        fs.<span class="title function_">open</span>(target, <span class="string">&#x27;w&#x27;</span>, <span class="keyword">function</span> (<span class="params">err, wfd</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (err) <span class="keyword">return</span> <span class="title function_">cb</span>(err)</span><br><span class="line">            <span class="keyword">let</span> readOffset = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">let</span> writeOffset = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">function</span> <span class="title function_">next</span>(<span class="params"></span>) &#123;</span><br><span class="line">                fs.<span class="title function_">read</span>(fd, buffer, <span class="number">0</span>, <span class="variable constant_">BUFFER_SIZE</span>, readOffset, <span class="keyword">function</span> (<span class="params">err, bytesRead</span>) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (err) <span class="keyword">return</span> <span class="title function_">cb</span>(err)</span><br><span class="line">                    <span class="keyword">if</span> (bytesRead == <span class="number">0</span>) &#123;</span><br><span class="line">                        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;copy完整&#x27;</span>)</span><br><span class="line">                        fs.<span class="title function_">close</span>(fd, <span class="keyword">function</span> (<span class="params"></span>) &#123; &#125;)</span><br><span class="line">                        fs.<span class="title function_">close</span>(wfd, <span class="keyword">function</span> (<span class="params"></span>) &#123; &#125;)</span><br><span class="line">                        <span class="keyword">return</span></span><br><span class="line">                    &#125;</span><br><span class="line">                    fs.<span class="title function_">write</span>(wfd, buffer, <span class="number">0</span>, bytesRead, writeOffset, <span class="keyword">function</span> (<span class="params">err, written</span>) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (err) <span class="keyword">return</span> <span class="title function_">cb</span>(err)</span><br><span class="line">                        readOffset += written</span><br><span class="line">                        writeOffset = readOff<span class="keyword">set</span></span><br><span class="line">                        <span class="title function_">next</span>();</span><br><span class="line">                    &#125;)</span><br><span class="line">                &#125;)</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="title function_">next</span>()</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 问题？回调地狱   出错了不能统一处理  没法控制暂停  读写没有分离  读写的打开顺序（不应该有顺序）</span></span><br><span class="line"><span class="comment">// 发布订阅来解耦代码</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>ReadStream</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title class_">EventEmitter</span> = <span class="built_in">require</span>(<span class="string">&#x27;events&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ReadStream</span> <span class="keyword">extends</span> <span class="title class_ inherited__">EventEmitter</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">path, options = &#123;&#125;</span>) &#123;</span><br><span class="line">        <span class="variable language_">super</span>()</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">path</span> = path;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">flags</span> = options.<span class="property">flags</span> || <span class="string">&#x27;r&#x27;</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">encoding</span> = options.<span class="property">encoding</span> || <span class="literal">null</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">emitClose</span> = options.<span class="property">emitClose</span> || <span class="literal">false</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">start</span> = options.<span class="property">start</span> || <span class="number">0</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">end</span> = options.<span class="property">end</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">highWaterMark</span> = options.<span class="property">highWaterMark</span> || <span class="number">64</span> * <span class="number">1024</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">open</span>();</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">flowing</span> = <span class="literal">false</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">on</span>(<span class="string">&#x27;newListener&#x27;</span>, <span class="function">(<span class="params">type</span>) =&gt;</span> &#123; <span class="comment">// events</span></span><br><span class="line">            <span class="keyword">if</span> (type == <span class="string">&#x27;data&#x27;</span>) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">flowing</span> = <span class="literal">true</span>;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">read</span>(); <span class="comment">// 同步调用read</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">offset</span> = <span class="variable language_">this</span>.<span class="property">start</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">resume</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">flowing</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">flowing</span> = <span class="literal">true</span>; <span class="comment">// 恢复流动模式</span></span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">read</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">pause</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">flowing</span> = <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">read</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="comment">// fs.read()</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="variable language_">this</span>.<span class="property">fd</span> !== <span class="string">&#x27;number&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">once</span>(<span class="string">&#x27;open&#x27;</span>, <span class="function">() =&gt;</span> <span class="variable language_">this</span>.<span class="title function_">read</span>())</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">const</span> howMuchToRead = <span class="variable language_">this</span>.<span class="property">end</span> ? <span class="title class_">Math</span>.<span class="title function_">min</span>(<span class="variable language_">this</span>.<span class="property">end</span> - <span class="variable language_">this</span>.<span class="property">offset</span> + <span class="number">1</span>, <span class="variable language_">this</span>.<span class="property">highWaterMark</span>) : <span class="variable language_">this</span>.<span class="property">highWaterMark</span></span><br><span class="line">        <span class="keyword">let</span> buffer = <span class="title class_">Buffer</span>.<span class="title function_">alloc</span>(howMuchToRead);</span><br><span class="line">        fs.<span class="title function_">read</span>(<span class="variable language_">this</span>.<span class="property">fd</span>, buffer, <span class="number">0</span>, buffer.<span class="property">length</span>, <span class="variable language_">this</span>.<span class="property">offset</span>, <span class="function">(<span class="params">err, bytesRead</span>) =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (bytesRead) &#123;</span><br><span class="line">                <span class="comment">// 我们预期的buffer是100个字节 但是真实读取到的只有6个</span></span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">emit</span>(<span class="string">&#x27;data&#x27;</span>, buffer.<span class="title function_">slice</span>(<span class="number">0</span>, bytesRead));</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">offset</span> += bytesRead;</span><br><span class="line">                <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">flowing</span>) &#123;</span><br><span class="line">                    <span class="variable language_">this</span>.<span class="title function_">read</span>();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">emit</span>(<span class="string">&#x27;end&#x27;</span>);</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">destroy</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">destroy</span>(<span class="params">err</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (err) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">emit</span>(<span class="string">&#x27;error&#x27;</span>, err)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">fd</span>) &#123;</span><br><span class="line">            fs.<span class="title function_">close</span>(<span class="variable language_">this</span>.<span class="property">fd</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">emitClose</span>) &#123;</span><br><span class="line">                    <span class="variable language_">this</span>.<span class="title function_">emit</span>(<span class="string">&#x27;close&#x27;</span>)</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">open</span>(<span class="params"></span>) &#123;</span><br><span class="line">        fs.<span class="title function_">open</span>(<span class="variable language_">this</span>.<span class="property">path</span>, <span class="variable language_">this</span>.<span class="property">flags</span>, <span class="function">(<span class="params">err, fd</span>) =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (err) <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">destroy</span>(err);</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">fd</span> = fd;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">emit</span>(<span class="string">&#x27;open&#x27;</span>, fd)</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">pipe</span>(<span class="params">ws</span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="function"><span class="params">data</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">let</span> flag = ws.<span class="title function_">write</span>(data);</span><br><span class="line">            <span class="keyword">if</span> (!flag) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">pause</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">on</span>(<span class="string">&#x27;end&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            ws.<span class="title function_">end</span>(); <span class="comment">// 已经写入完毕了</span></span><br><span class="line">        &#125;)</span><br><span class="line">        ws.<span class="title function_">on</span>(<span class="string">&#x27;drain&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">resume</span>();</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="title class_">ReadStream</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>ReadStream</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1.</span></span><br><span class="line"><span class="comment">// 基于“文件”系统的可读流</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> <span class="title class_">ReadStream</span> = <span class="built_in">require</span>(<span class="string">&#x27;./ReadStream&#x27;</span>)</span><br><span class="line"><span class="keyword">let</span> rs = <span class="keyword">new</span> <span class="title class_">ReadStream</span>(path.<span class="title function_">resolve</span>(__dirname, <span class="string">&#x27;test&#x27;</span>), &#123;</span><br><span class="line">    <span class="comment">// let rs = fs.createReadStream(path.resolve(__dirname, &#x27;test&#x27;), &#123;</span></span><br><span class="line">    <span class="attr">flags</span>: <span class="string">&#x27;r&#x27;</span>,<span class="comment">// 默认flags就是r 表示读取操作</span></span><br><span class="line">    <span class="attr">encoding</span>: <span class="literal">null</span>, <span class="comment">// 默认读取出的数据是二进制格式</span></span><br><span class="line">    <span class="attr">emitClose</span>: <span class="literal">true</span>,<span class="comment">// 读取完毕后是否要触发close事件</span></span><br><span class="line">    <span class="attr">start</span>: <span class="number">0</span>, <span class="comment">// 从哪里开始读取</span></span><br><span class="line">    <span class="attr">end</span>: <span class="number">3</span>, <span class="comment">// 读取到什么位置 （包后 0-3是四个字节）</span></span><br><span class="line">    <span class="attr">highWaterMark</span>: <span class="number">3</span>, <span class="comment">// 每次读取文件的字节数 64*1024</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// 自己的权限  我所在组的权限 别人的权限  chmod -R 777</span></span><br><span class="line"><span class="comment">// rwxr-xr-x  权限   r 4 w 2 x 1  666</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 文件的可读流才具备open事件</span></span><br><span class="line">rs.<span class="title function_">on</span>(<span class="string">&#x27;open&#x27;</span>, <span class="keyword">function</span> (<span class="params">fd</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(fd)</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">rs.<span class="title function_">on</span>(<span class="string">&#x27;error&#x27;</span>, <span class="keyword">function</span> (<span class="params">err</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">let</span> arr = []</span><br><span class="line">rs.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="keyword">function</span> (<span class="params">data</span>) &#123; <span class="comment">// [123]</span></span><br><span class="line">    arr.<span class="title function_">push</span>(data);</span><br><span class="line">    rs.<span class="title function_">pause</span>();</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(data, <span class="number">29</span>);</span><br><span class="line">&#125;)</span><br><span class="line">rs.<span class="title function_">on</span>(<span class="string">&#x27;end&#x27;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Buffer</span>.<span class="title function_">concat</span>(arr).<span class="title function_">toString</span>());</span><br><span class="line">&#125;);</span><br><span class="line">rs.<span class="title function_">on</span>(<span class="string">&#x27;close&#x27;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;close&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">setInterval</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    rs.<span class="title function_">resume</span>(); <span class="comment">// 恢复data的触发</span></span><br><span class="line">    <span class="comment">//   rs.pause(); //  这个暂停意味着不在触发 data事件</span></span><br><span class="line">&#125;, <span class="number">1000</span>)</span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">// 如果用户监听了data事件，会将数据不停的发射出来</span></span><br><span class="line"><span class="comment">let arr = []</span></span><br><span class="line"><span class="comment">rs.on(&#x27;data&#x27;, function (data) &#123;</span></span><br><span class="line"><span class="comment">    arr.push(data)</span></span><br><span class="line"><span class="comment">&#125;)</span></span><br><span class="line"><span class="comment">rs.on(&#x27;end&#x27;, function () &#123;</span></span><br><span class="line"><span class="comment">    console.log(Buffer.concat(arr).toString());</span></span><br><span class="line"><span class="comment">&#125;);</span></span><br><span class="line"><span class="comment">rs.on(&#x27;error&#x27;, function (err) &#123;</span></span><br><span class="line"><span class="comment">    console.log(err)</span></span><br><span class="line"><span class="comment">&#125;)</span></span><br><span class="line"><span class="comment">// 文件的可读流才具备close事件</span></span><br><span class="line"><span class="comment">rs.on(&#x27;close&#x27;, function () &#123;</span></span><br><span class="line"><span class="comment">    console.log(&#x27;close&#x27;)</span></span><br><span class="line"><span class="comment">&#125;)</span></span><br><span class="line"><span class="comment">// setTimeout(() =&gt; &#123;</span></span><br><span class="line"><span class="comment">//     rs.resume(); // 恢复data的触发</span></span><br><span class="line"><span class="comment">//     rs.pause(); //  这个暂停意味着不在触发 data事件</span></span><br><span class="line"><span class="comment">// &#125;, 1000)</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">// on(&#x27;open&#x27;) on(&#x27;close&#x27;)  on(&#x27;data&#x27;) on(&#x27;end&#x27;)  on(&#x27;error&#x27;)  .pause() .resume() */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2.</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"><span class="keyword">let</span> rs = fs.<span class="title function_">createReadStream</span>(path.<span class="title function_">resolve</span>(__dirname, <span class="string">&#x27;test&#x27;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">// 调试可读流内部原理</span></span><br><span class="line"><span class="comment">// rs.on(&#x27;data&#x27;, function (data) &#123;</span></span><br><span class="line"><span class="comment">//     console.log(data, 29);</span></span><br><span class="line"><span class="comment">// &#125;)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 内部继承了一个类 Readable 父类  new ReadStream 是Readable子类</span></span><br><span class="line"><span class="comment">// ReflectApply(Readable, this, [options]);   Readable.call(this)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// ObjectSetPrototypeOf(ReadStream.prototype, Readable.prototype); 子类继承父类的原型方法</span></span><br><span class="line"><span class="comment">// 父类提供了一个Readable.prototype.read方法 （内部会检测用户监听了data事件） 就会调用read方法</span></span><br><span class="line"><span class="comment">// 父类调用子类的this._read， 内部采用的是 fs.read方法来进行读取的</span></span><br><span class="line"><span class="comment">// 将读取的数据调用 this.push()  -&gt; this.emit(&#x27;data&#x27;,chunk)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 我们可以自定义可读流</span></span><br><span class="line"><span class="keyword">let</span> clientData = <span class="string">&#x27;hello world&#x27;</span></span><br><span class="line"><span class="keyword">const</span> &#123; <span class="title class_">Readable</span> &#125; = <span class="built_in">require</span>(<span class="string">&#x27;stream&#x27;</span>)</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyReadStream</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Readable</span> &#123;</span><br><span class="line">    <span class="title function_">_read</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">push</span>(clientData);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">push</span>(<span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> mrs = <span class="keyword">new</span> <span class="title class_">MyReadStream</span>();</span><br><span class="line"><span class="comment">// 不具备 close open 方法， 因为不是文件</span></span><br><span class="line">mrs.<span class="title function_">on</span>(<span class="string">&#x27;data&#x27;</span>, <span class="keyword">function</span> (<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(data);</span><br><span class="line">&#125;)</span><br><span class="line">mrs.<span class="title function_">on</span>(<span class="string">&#x27;end&#x27;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;结束&#x27;</span>)</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 以后见到能on(&#x27;data&#x27;) on(&#x27;end&#x27;) 一定是一个可读流</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 3.</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> ws = fs.<span class="title function_">createWriteStream</span>(path.<span class="title function_">resolve</span>(__dirname, <span class="string">&#x27;test1&#x27;</span>), &#123;</span><br><span class="line">    <span class="attr">flags</span>: <span class="string">&#x27;w&#x27;</span>, <span class="comment">// fs.open()</span></span><br><span class="line">    <span class="attr">encoding</span>: <span class="string">&#x27;utf8&#x27;</span>, <span class="comment">// 编码格式  （一个文件能写一半gbk和一半utf8）</span></span><br><span class="line">    <span class="attr">mode</span>: <span class="number">438</span>,</span><br><span class="line">    <span class="attr">start</span>: <span class="number">0</span>,</span><br><span class="line">    <span class="attr">highWaterMark</span>: <span class="number">3</span> <span class="comment">// （读取的时候 代表每次能读取多少个，但是写入的时候表示的是我期望使用的内存大小</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 每次open的时候 会清空文件</span></span><br><span class="line"><span class="comment">// 可写流有三个方法 write()  write.end()  </span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> flag = ws.<span class="title function_">write</span>(<span class="string">&#x27;ok&#x27;</span>); <span class="comment">// fs.write 如何解决多个异步的并发问题</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(flag)</span><br><span class="line">flag = ws.<span class="title function_">write</span>(<span class="string">&#x27;o&#x27;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(flag)</span><br><span class="line"></span><br><span class="line"><span class="comment">// drain事件有一个触发条件 就是需要保证达到预期后清空内存才会触发</span></span><br><span class="line">ws.<span class="title function_">on</span>(<span class="string">&#x27;drain&#x27;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;diran&#x27;</span>, <span class="string">&#x27;都写入成功了&#x27;</span>);</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 4.</span></span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"><span class="comment">// const WriteStream = require(&#x27;./WriteStream&#x27;);</span></span><br><span class="line"><span class="comment">// // let ws = new WriteStream(path.resolve(__dirname, &#x27;test1&#x27;), &#123;</span></span><br><span class="line"><span class="comment">// let ws = fs.createWriteStream(path.resolve(__dirname, &#x27;test1&#x27;), &#123;</span></span><br><span class="line"><span class="comment">//     flags: &#x27;w&#x27;,</span></span><br><span class="line"><span class="comment">//     encoding: &#x27;utf8&#x27;,</span></span><br><span class="line"><span class="comment">//     mode: 438,</span></span><br><span class="line"><span class="comment">//     start: 0,</span></span><br><span class="line"><span class="comment">//     highWaterMark: 3</span></span><br><span class="line"><span class="comment">// &#125;);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// let flag = ws.write(&#x27;ok&#x27;);</span></span><br><span class="line"><span class="comment">// flag = ws.write(&#x27;o&#x27;);</span></span><br><span class="line"><span class="comment">// flag = ws.write(&#x27;k&#x27;);</span></span><br><span class="line"><span class="comment">// ws.on(&#x27;drain&#x27;, function () &#123;</span></span><br><span class="line"><span class="comment">//     console.log(&#x27;diran&#x27;, &#x27;都写入成功了&#x27;);</span></span><br><span class="line"><span class="comment">//     // let flag = ws.write(&#x27;ok&#x27;);</span></span><br><span class="line"><span class="comment">// &#125;);</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// ws.end(&#x27;哈哈&#x27;) // = write + close</span></span><br><span class="line"><span class="comment">// 1） 为了实现可以对可写流的扩展  WriteStream 继承于父类 Writable</span></span><br><span class="line"><span class="comment">// 2) 父类有一个方法write()  子类有一个方法_write  this._write</span></span><br><span class="line"><span class="keyword">const</span> &#123; <span class="title class_">Writable</span>, <span class="title class_">Duplex</span> &#125; = <span class="built_in">require</span>(<span class="string">&#x27;stream&#x27;</span>)</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyWriteStream</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Duplex</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="variable language_">super</span>(&#123; <span class="attr">highWaterMark</span>: <span class="number">2</span> &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">_read</span>(<span class="params"></span>) &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">_write</span>(<span class="params">data, encoding, clearBuffer</span>) &#123; <span class="comment">// callback -》 clearBuffer</span></span><br><span class="line">        <span class="comment">// fs.write()</span></span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(data)</span><br><span class="line">        <span class="title function_">clearBuffer</span>()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> ms = <span class="keyword">new</span> <span class="title class_">MyWriteStream</span>();</span><br><span class="line">ms.<span class="title function_">write</span>(<span class="string">&#x27;ok&#x27;</span>); <span class="comment">// 只有第一次调用write会正在的写入到文件中 _write</span></span><br><span class="line">ms.<span class="title function_">write</span>(<span class="string">&#x27;ok&#x27;</span>)</span><br><span class="line">ms.<span class="title function_">write</span>(<span class="string">&#x27;ok&#x27;</span>)</span><br><span class="line"></span><br><span class="line">ms.<span class="title function_">on</span>(<span class="string">&#x27;drain&#x27;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123; <span class="comment">//  drain 是WriteStream里面实现的</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;drain&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br></pre></td></tr></table></figure>
</li>
<li><p>pipe</p>
</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"><span class="keyword">let</span> rs = fs.<span class="title function_">createReadStream</span>(path.<span class="title function_">resolve</span>(__dirname, <span class="string">&#x27;test&#x27;</span>), &#123;</span><br><span class="line">    <span class="attr">highWaterMark</span>: <span class="number">4</span> <span class="comment">// 每次读取4个</span></span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">let</span> ws = fs.<span class="title function_">createWriteStream</span>(path.<span class="title function_">resolve</span>(__dirname, <span class="string">&#x27;test1&#x27;</span>), &#123; <span class="comment">//  createWriteStream 有缓存的概念</span></span><br><span class="line">    <span class="attr">highWaterMark</span>: <span class="number">1</span> <span class="comment">// 我期望使用一个字节的内存大小来控制</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// pipe</span></span><br><span class="line"></span><br><span class="line">rs.<span class="title function_">pipe</span>(ws); <span class="comment">// 看不到写入的过程， 此方法是异步的方法</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">rs.on(&#x27;data&#x27;, function (data) &#123;</span></span><br><span class="line"><span class="comment">    let flag = ws.write(data);</span></span><br><span class="line"><span class="comment">    if (!flag) &#123; // 已经超过我的预期了，再给我会浪费内存，先别读取</span></span><br><span class="line"><span class="comment">        rs.pause();</span></span><br><span class="line"><span class="comment">    &#125;</span></span><br><span class="line"><span class="comment">&#125;)</span></span><br><span class="line"><span class="comment">ws.on(&#x27;drain&#x27;, function () &#123;</span></span><br><span class="line"><span class="comment">    console.log(&#x27;分段读取&#x27;)</span></span><br><span class="line"><span class="comment">    rs.resume(); // 回复继续读取，继续触发data事件</span></span><br><span class="line"><span class="comment">&#125;) */</span></span><br></pre></td></tr></table></figure>

<ul>
<li><p>process</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 监听进程的标准输入， 用户可以和命令行做交互操作</span></span><br><span class="line"><span class="comment">// 初始化一个项目 需要用户输入用户名称：</span></span><br><span class="line"><span class="comment">// process.stdin.on(&#x27;data&#x27;, function (data) &#123; // 可以用于进程间的通信。 可以用于进程间的交互 </span></span><br><span class="line"><span class="comment">//     // console.log(data)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//     // 标准输出和console.log功能一样</span></span><br><span class="line"><span class="comment">//     // 错误输出 console.err</span></span><br><span class="line"><span class="comment">//     process.stderr.write(data); // 可写流</span></span><br><span class="line"><span class="comment">// &#125;);</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 压缩流、加密的流 </span></span><br><span class="line"></span><br><span class="line"><span class="comment">// a  -&gt; 转化过程（转化流）  -&gt; b</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> &#123; <span class="title class_">Transform</span> &#125; = <span class="built_in">require</span>(<span class="string">&#x27;stream&#x27;</span>)</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyTransform</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Transform</span> &#123;</span><br><span class="line">    <span class="title function_">_transform</span>(<span class="params">chunk, encoding, clearBuffer</span>) &#123;<span class="comment">// 具备_write的参数 也具备可读流的push方法</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">push</span>(chunk.<span class="title function_">toString</span>().<span class="title function_">toUpperCase</span>())</span><br><span class="line">        <span class="title function_">clearBuffer</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> transform = <span class="keyword">new</span> <span class="title class_">MyTransform</span>()</span><br><span class="line"></span><br><span class="line">process.<span class="property">stdin</span>.<span class="title function_">pipe</span>(transform).<span class="title function_">pipe</span>(process.<span class="property">stdout</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 文件的可读流和可写流 （解耦，异步并发  fs.createReadStream(on(&#x27;data&#x27;) on(&#x27;end&#x27;)) writeStream(write end) ）</span></span><br><span class="line"><span class="comment">// 怎么实现自定义的流  思想</span></span><br><span class="line"><span class="comment">// pipe 方法的实现是一个边读编写的过程</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 文件夹操作，tcp 和 http </span></span><br></pre></td></tr></table></figure>
</li>
<li><p>writeStream</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title class_">EventEmitter</span> = <span class="built_in">require</span>(<span class="string">&#x27;events&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">WriteStream</span> <span class="keyword">extends</span> <span class="title class_ inherited__">EventEmitter</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">path, options = &#123;&#125;</span>) &#123;</span><br><span class="line">        <span class="variable language_">super</span>();</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">path</span> = path;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">flags</span> = options.<span class="property">flags</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">encoding</span> = options.<span class="property">encoding</span> || <span class="string">&#x27;utf8&#x27;</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">mode</span> = options.<span class="property">mode</span> || <span class="number">438</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">start</span> = options.<span class="property">start</span> || <span class="number">0</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">highWaterMark</span> = options.<span class="property">highWaterMark</span> || <span class="number">16</span> * <span class="number">1024</span>;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">len</span> = <span class="number">0</span>; <span class="comment">// 维护写入的个数和长度</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">writing</span> = <span class="literal">false</span>; <span class="comment">// 是否正在写入来区分放到缓存区还是写入文件中</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">cache</span> = []; <span class="comment">// 用于缓存除了第一次写入的逻辑</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">needDrain</span> = <span class="literal">false</span>; <span class="comment">// 是否要触发drain事件</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">offset</span> = <span class="variable language_">this</span>.<span class="property">start</span>; <span class="comment">// 写入的偏移量</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">open</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">end</span>(<span class="params">chunk = <span class="string">&#x27;&#x27;</span>, encoding = <span class="variable language_">this</span>.encoding, callback = () =&gt; &#123; &#125;</span>) &#123;</span><br><span class="line">        chunk = <span class="title class_">Buffer</span>.<span class="title function_">isBuffer</span>(chunk) ? chunk : <span class="title class_">Buffer</span>.<span class="title function_">from</span>(chunk);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">write</span>(chunk, encoding, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">needDrain</span> = <span class="literal">false</span>;</span><br><span class="line">            <span class="title function_">callback</span>();</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">clearBuffer</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> cur = <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">shift</span>(); <span class="comment">// 在队列中拿出第一个</span></span><br><span class="line">        <span class="keyword">if</span> (cur) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">_write</span>(cur.<span class="property">chunk</span>, cur.<span class="property">encoding</span>, cur.<span class="property">callback</span>)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 是否要触发drain事件</span></span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">writing</span> = <span class="literal">false</span>; <span class="comment">// 触发drain的时候 下次写入可以在向文件中继续写入</span></span><br><span class="line">            <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">needDrain</span>) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">needDrain</span> = <span class="literal">false</span>;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">emit</span>(<span class="string">&#x27;drain&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">write</span>(<span class="params">chunk, encoding = <span class="variable language_">this</span>.encoding, callback = () =&gt; &#123; &#125;</span>) &#123;</span><br><span class="line">        <span class="comment">// 统一写入的数据格式</span></span><br><span class="line">        chunk = <span class="title class_">Buffer</span>.<span class="title function_">isBuffer</span>(chunk) ? chunk : <span class="title class_">Buffer</span>.<span class="title function_">from</span>(chunk);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">len</span> += chunk.<span class="property">length</span>;</span><br><span class="line">        <span class="keyword">let</span> returnValue = <span class="variable language_">this</span>.<span class="property">len</span> &lt; <span class="variable language_">this</span>.<span class="property">highWaterMark</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">needDrain</span> = !returnValue; <span class="comment">// 如果写入的数据达到了预期才应该触发needDrain</span></span><br><span class="line">        <span class="keyword">const</span> <span class="title function_">clear</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">clearBuffer</span>();</span><br><span class="line">            <span class="title function_">callback</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">writing</span>) &#123;</span><br><span class="line">            <span class="comment">// 向缓存中写入</span></span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">cache</span>.<span class="title function_">push</span>(&#123;</span><br><span class="line">                chunk,</span><br><span class="line">                encoding,</span><br><span class="line">                <span class="attr">callback</span>: clear</span><br><span class="line">            &#125;); <span class="comment">// 多个异步同时操作 可以采用队列的方式来记录</span></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">writing</span> = <span class="literal">true</span>;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">_write</span>(chunk, encoding, clear);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> returnValue</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">_write</span>(<span class="params">chunk, encoding, callback</span>) &#123;</span><br><span class="line">        <span class="comment">// 调用fs.write写入</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="variable language_">this</span>.<span class="property">fd</span> !== <span class="string">&#x27;number&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">once</span>(<span class="string">&#x27;open&#x27;</span>, <span class="function">() =&gt;</span> <span class="variable language_">this</span>.<span class="title function_">_write</span>(chunk, encoding, callback))</span><br><span class="line">        &#125;</span><br><span class="line">        fs.<span class="title function_">write</span>(<span class="variable language_">this</span>.<span class="property">fd</span>, chunk, <span class="number">0</span>, chunk.<span class="property">length</span>, <span class="variable language_">this</span>.<span class="property">offset</span>, <span class="function">(<span class="params">err, written</span>) =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">len</span> -= written; <span class="comment">// 写入后 减少正在写入的个数</span></span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">offset</span> += written;</span><br><span class="line">            <span class="title function_">callback</span>();</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">open</span>(<span class="params"></span>) &#123;</span><br><span class="line">        fs.<span class="title function_">open</span>(<span class="variable language_">this</span>.<span class="property">path</span>, <span class="variable language_">this</span>.<span class="property">flags</span>, <span class="variable language_">this</span>.<span class="property">mode</span>, <span class="function">(<span class="params">error, fd</span>) =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (error) <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">destroy</span>(error);</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">fd</span> = fd;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">emit</span>(<span class="string">&#x27;open&#x27;</span>, fd)</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">destroy</span>(<span class="params">err</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (err) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">emit</span>(<span class="string">&#x27;error&#x27;</span>, err)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">fd</span>) &#123;</span><br><span class="line">            fs.<span class="title function_">close</span>(<span class="variable language_">this</span>.<span class="property">fd</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">emitClose</span>) &#123;</span><br><span class="line">                    <span class="variable language_">this</span>.<span class="title function_">emit</span>(<span class="string">&#x27;close&#x27;</span>)</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="title class_">WriteStream</span></span><br></pre></td></tr></table></figure></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/wieldy/bailment-blog/2022/03/29/stream/" data-id="cljmgj1f0000ozc9j0m2f1xhm" data-title="stream" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/bailment-blog/2022/03/29/node/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          node
        
      </div>
    </a>
  
  
    <a href="/bailment-blog/2022/03/29/vue3-1.reactivity/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">1.reactivity</div>
    </a>
  
</nav>

  
</article>


</section>
        
          <aside id="sidebar">
  
    

  
    

  
    
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/bailment-blog/archives/2023/07/">July 2023</a></li><li class="archive-list-item"><a class="archive-list-link" href="/bailment-blog/archives/2023/06/">June 2023</a></li><li class="archive-list-item"><a class="archive-list-link" href="/bailment-blog/archives/2023/04/">April 2023</a></li><li class="archive-list-item"><a class="archive-list-link" href="/bailment-blog/archives/2023/03/">March 2023</a></li><li class="archive-list-item"><a class="archive-list-link" href="/bailment-blog/archives/2022/03/">March 2022</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/bailment-blog/2023/07/03/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/">工作日志</a>
          </li>
        
          <li>
            <a href="/bailment-blog/2023/06/29/payMent/">payMent</a>
          </li>
        
          <li>
            <a href="/bailment-blog/2023/06/20/%E7%BD%91%E7%BA%A2%E9%9D%A2%E8%AF%95%E9%A2%98/">原理题</a>
          </li>
        
          <li>
            <a href="/bailment-blog/2023/06/19/%E5%89%8D%E7%AB%AF%E5%A4%A7%E5%B1%8F%E8%87%AA%E9%80%82%E5%BA%94%E6%96%B9%E6%B3%95/">前端大屏自适应方法</a>
          </li>
        
          <li>
            <a href="/bailment-blog/2023/06/17/10%E4%B8%AAJavaScript%E5%B8%B8%E8%A7%81%E9%AB%98%E7%BA%A7%E7%9F%A5%E8%AF%86%E7%82%B9/">10个JavaScript常见高级知识点</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      
      &copy; 2023 John Doe<br>
      Powered by <a href="https://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>

    </div>
    <nav id="mobile-nav">
  
    <a href="/bailment-blog/" class="mobile-nav-link">Home</a>
  
    <a href="/bailment-blog/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="/bailment-blog/js/jquery-3.4.1.min.js"></script>



  
<script src="/bailment-blog/fancybox/jquery.fancybox.min.js"></script>




<script src="/bailment-blog/js/script.js"></script>





  </div>
</body>
</html>